﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Linq.Expressions;

namespace MetaDrive.FluentCode
{  
    public class FluentCodeQuery<T> : IFluentCodeQuery where T : IFluentCodeElement
    {
        public T Element { get; private set; }
    
        public FluentCodeQuery(T element)
        {
            this.Element = element;
        }
     
        protected EnvDTE.CodeElements GetCodeElements()
        {
            EnvDTE.CodeElements elements = null;

            if (Element.Adaptee as EnvDTE80.FileCodeModel2 != null)
                elements = ((EnvDTE80.FileCodeModel2)Element.Adaptee).CodeElements;

            if (Element.Adaptee as EnvDTE.CodeElement != null)
                elements = ((EnvDTE80.CodeElement2)Element.Adaptee).Children;

            return elements;
        }

        protected IEnumerable<EnvDTE.CodeElement> CreateCodeElementIterator()
        {
            EnvDTE.CodeElements elements = GetCodeElements();
            if (elements != null)
                return new CodeElementIterator(elements);

            return null;
        }

        public IEnumerable<IFluentCodeElement> Children
        {
            get
            {
                EnvDTE.CodeElements elements = GetCodeElements();

                if (elements != null)
                {
                    foreach (EnvDTE.CodeElement element in elements)
                    {
                        if (element != null)
                        {
                            var f = element.ToFluentCodeElement();
                            if (f == null)
                            {
                                // do nothing
                            }
                            else
                            {
                                yield return element.ToFluentCodeElement();
                            }
                        }
                    }
                }
            }
        }

        public IEnumerable<IFluentCodeElement> Elements
        {
            get
            {
                var iterator = CreateCodeElementIterator();
                if (iterator != null)
                    return iterator.Select(x => x.ToFluentCodeElement()).Cast<IFluentCodeElement>().AsEnumerable<IFluentCodeElement>();

                return null;
            }
        }
    
        public IEnumerable<T> OfType<T>() where T : IFluentCodeElement
        {
            var iterator = CreateCodeElementIterator();
            return iterator.ToFluentCodeElement<T>();   
        }

        public IEnumerable<IFluentCodeElement> ByName(string elementName)
        {
            return CreateCodeElementIterator().
                Where(x => x.Name == elementName).
                ToFluentCodeElement();
        }

        public IEnumerable<T> ByName<T>(string elementName) where T : IFluentCodeElement
        {
            return CreateCodeElementIterator().
                Where(x => x.Name == elementName).
                ToFluentCodeElement<T>();
        }
    }
}
